/**************************************************************************
*   Copyleft 2009 by        											  *
*	Iwanicki Krzysztof													  *
*   <www.gamma.mini.pw.edu.pl/~iwanickik>		                          *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
***************************************************************************/
#ifndef __VCAMERA_H__
#define __VCAMERA_H__

#include "../Renderer/vFrameListener.h"
#include "../../Utils/vUtils.h"
#include <Math/vMath.h>
#include "../../Macros/vMemoryMacros.h"

// TODO: Change later if used this camera to call addCamerera to scene mananger in camera ctor.
// TODO: Add FOV and perspective set.
namespace Vendetta {
	class vSceneManager;

	/*! \class vCamera
	 *  \brief A vCamera class is pure abstract.
	 *
	 *  All camera types should implement it.
	 */
	class vCamera {
		friend class vSceneManager;
	public:
		/*! \brief Method called to update data before rendering starts.
		 *
		 *	\param		event			vFrameEvent structure containing useful information.
		 */
		virtual vVoid Update(const vFrameListener::vFrameEvent& event) = 0;

		/*! \brief Applies view to the API.
		 *
		 */	
		virtual vVoid Use();
		
		/*! \brief Returns camera name.
		 *
		 *	\return		vString			Camera name.
		 */	
		inline const vString& Name() const { return mName; }

		/*! \brief Returns camera position in world coordinates.
		 *
		 *	\return		vPoint3D		Camera position.
		 */	
		inline vPoint3D Position() const { return mPosition; }

		/*! \brief Sets camera position in world coordinates.
		 *
		 *	\param		position		Camera position.
		 */	
		inline vVoid SetPosition(vPoint3D position) { mPosition = position; }


		/*! \brief Returns camera speed vector.
		 *
		 *	\return		vVector3D		Camera speed vector.
		 */	
		inline vVector3D Speed() const { return mSpeed; }

		/*! \brief Sets camera speed vector.
		 *
		 *	\param		speed			Camera speed vector.
		 */	
		inline vVoid SetSpeed(vVector3D speed) { mSpeed = speed; }

		/*! \brief Returns camera target point to look at.
		 *
		 *	\return		vPoint3D		Camera target point.
		 */	
		inline vPoint3D Target() const { return mTarget; }

		/*! \brief Sets camera target point to look at.
		 *
		 *	\param		target			Camera target point.
		 */	
		inline vVoid SetTarget(vPoint3D target) { mTarget = target; }


		/*! \brief Returns camera up vector.
		 *
		 *	\return		vVector3D		Camera up vector.
		 */
		inline vVector3D UpDir() const { return mUpDir; }

		/*! \brief Sets camera up vector.
		 *
		 *	\param		mUpDir			Camera up vector.
		 */	
		inline vVoid SetUpDir(vVector3D upDir) { mUpDir = upDir; }

		/*! \brief Returns camera right vector.
		 *
		 *	\return		vVector3D		Camera right vector.
		 */	
		inline vVector3D RightDir() const { return mRightDir; }

		/*! \brief Sets camera right vector.
		 *
		 *	\param		rightDir		Camera right vector.
		 */	
		inline vVoid SetRightDir(vVector3D rightDir) { mRightDir = rightDir; }

		/*! \brief Returns camera field of view.
		 *
		 *	\return		vReal			Camera near plane.
		 */	
		inline vReal Fov() const { return mFov; }

		/*! \brief Sets camera field of view.
		 *
		 *	\return		fov				Camera near plane.
		 */	
		inline vVoid Fov(vReal fov) { mFov = fov;}

		/*! \brief Returns camera near plane.
		 *
		 *	\return		vReal			Camera near plane.
		 */	
		inline vReal NearPlane() const { return mNearPlane; }

		/*! \brief Sets camera near plane.
		 *
		 *	\return		nearPlane		Camera near plane.
		 */	
		inline vVoid NearPlane(vReal nearPlane) { mNearPlane = nearPlane;}

		/*! \brief Returns camera far plane.
		 *
		 *	\return		vReal			Camera far plane.
		 */	
		inline vReal FarPlane() const { return mFarPlane; }

		/*! \brief Sets camera far plane.
		 *
		 *	\return		farPlane		Camera far plane.
		 */	
		inline vVoid FarPlane(vReal farPlane) { mFarPlane = farPlane;}

	protected:
		/*! \brief Constructor.
		 *
		 *	Note:	Camera must have owner as scene manager.
		 *			Camera name must be unique in context of scene manager.
		 *
		 *	\param		name			Camera name.
		 */	
		vCamera(const vString& name);

		/*! \brief Destructor.
		 *
		 */	
		virtual ~vCamera();

		/*! \brief Update projection view.
		 *
		 *	Note:	This method is called in case when far plane, near plane
		 *			or fov is changed.
		 */	
		vVoid updateProjection() const;

		//! Disabled - if You call this You get exception.
		vCamera();

		//! Disabled - if You call this You get exception.
		vCamera(const vCamera& camera);

		//! Disabled - if You call this You get exception.
		vCamera& operator=(const vCamera& camera);

	protected:
		vString				mName;				//!	Camera name.
		vPoint3D			mPosition;			//!	Camera position in world coords.		
		vPoint3D			mTarget;			//! Target point to look at.
		vVector3D			mUpDir;				//! Up direction vector.
		vVector3D			mRightDir;			//! Right direction vector.
		vVector3D			mSpeed;				//!	Speed vector.
		vReal				mFov;				//! Field of view value;
		vReal				mNearPlane;			//! Near plane distance.
		vReal				mFarPlane;			//! Far plane distance.
	};
}

#endif // __VCAMERA_H__